package main
import (
	"fmt"
        "io/ioutil"
	"os"
	"io"
	"strconv"
	"strings"
        "log"
	"net"
	"net/http"
	"time"
)

var httpLog   *log.Logger
var timout    int
var delay     int
var timeStamp int64
var RemoteUrl string
var SrsDir    string
var fetchTime bool
var client    *http.Client
var httpchan = make(chan int, 1)

func parseTimetoStamp(tim string, rLog *log.Logger) (int64, bool) {
        loc, _ := time.LoadLocation("Local")
        timeLayout := "2006-01-02 15:04:05"
        theTime, err := time.ParseInLocation(timeLayout, tim, loc)
        if err != nil {
                rLog.Println(err)
                return 0, false
        }
        srs := theTime.Unix()
        return srs, true
}

//http short-connection
func initHttps() *http.Client {
        client:=&http.Client {
                Transport :&http.Transport{
                        Dial: func(netw,addr string) (net.Conn,error) {
                                conn,err:=net.DialTimeout(netw,addr,time.Second*(time.Duration(timout)))
                                if err!=nil{
                                        return nil,err
                                }
                                conn.SetDeadline(time.Now().Add(time.Second*(time.Duration(timout))))
                                return conn,nil
                        },
                        ResponseHeaderTimeout: time.Second*(time.Duration(timout)),
                },
        }
        return client
}

//http long_connection
func initHttpl() *http.Client {
          client:=&http.Client {
                Transport :&http.Transport{
                        Dial: func(netw,addr string) (net.Conn,error) {
                                conn,err:=net.Dial(netw,addr)
                                if err!=nil{
                                        return nil,err
                                }
                                return conn,nil
                        },
                },
        }
        return client
}

func checkFileNotExist(FileName string) bool{
        if _,err:=os.Stat(FileName);err!=nil {
                        if os.IsNotExist(err) {
                                return true
                        }
        
        }
        return false
}

func copyFile(source,dest string) bool {
	if source == ""||dest == "" {
		httpLog.Printf("source or dest is null")
		return false
	}
	source_open,err:=os.Open(source)
	if err!=nil {
		httpLog.Println(err)
		return false
	}
	defer source_open.Close()
	dest_open,err :=os.OpenFile(dest,os.O_CREATE|os.O_WRONLY,644)
	if err!=nil {
		httpLog.Println(err)
		return false
	}
	defer dest_open.Close()
	_, copy_err:=io.Copy(dest_open,source_open)
	if copy_err!=nil {
		httpLog.Println(copy_err)
		return false
	}else {
		return true
	}
}
	

func putFile(filename string,newfilename string, client *http.Client) error {
	defer func() {
                if err:=recover();err!=nil {
                        httpLog.Println(err)
                }
        }()
	file,err:=os.OpenFile(filename,os.O_RDWR,0)
	defer file.Close()
	if err!=nil {
		return err
	}
	fmt.Printf("transcode_upload: local_file  == %s\n",filename)
	fmt.Printf("transcode_upload: remote_file == %s\n",RemoteUrl+"/"+newfilename) 
	reqest,err:=http.NewRequest("PUT",RemoteUrl+"/"+newfilename,file)
	if err!=nil {
		httpLog.Println(err)
		return err
	}
	reqest.Header.Set("Conntection","keep-alive")
	resp,err:=client.Do(reqest)
	if err!=nil  {
		httpLog.Println(err)
		return err
	}
	fmt.Printf("HTTP PUT request success: [%s]\n",RemoteUrl+"/"+newfilename)
	defer resp.Body.Close()
	resp_body,err:=ioutil.ReadAll(resp.Body)
	if err!=nil {
		return err
	}
	httpLog.Printf(string(resp_body))
	httpLog.Printf("End to putFile for %s.",filename)
	return nil
}

func startDelayTicker() {
	timer1:=time.NewTicker(time.Duration(delay)*time.Second)
	select {
		case <-timer1.C:
			httpchan<-1
		break
	}
}

func renameFile () {
	var tsFileName,filename,m3u8File string

	m3u8File=""
	if !checkFileNotExist(SrsDir+"/"+"01.m3u8"){
		m3u8File="01.m3u8"
	}else if !checkFileNotExist(SrsDir+"/"+"index.m3u8") {
		m3u8File="index.m3u8"
	}
        if m3u8File=="" {
		return
        }

	filename=getTsFileName(SrsDir+"/"+m3u8File)
	if filename=="" {
		return
	}
        tsFileName=SrsDir+"/"+filename

        if !checkFileNotExist(tsFileName){
		if !fetchTime {
			fetchTime=true
			tNow := time.Now()
        		timeNow := tNow.Format("2006-01-02 15:04:05")
       			timeStamp, _= parseTimetoStamp(timeNow, httpLog)
			go startDelayTicker()
		}
        	newtsfilename:=fmt.Sprintf("%d.ts",timeStamp)
               	err:=os.Rename(tsFileName,SrsDir+"/"+newtsfilename)
		if err!=nil {
                	httpLog.Printf("rename file error,file name is %s.\n",tsFileName)
                }
               	newm3u8filename:=fmt.Sprintf("%d.m3u8",timeStamp)
                suc:=copyFile(SrsDir+"/"+m3u8File,SrsDir+"/"+newm3u8filename)
                if !suc {
                	httpLog.Printf("rename file error,file name is %s.\n",m3u8File)
               	}
	}
	
	timeStamp=timeStamp+10
}

func getTsFileName(m3u8FileName string) string {
	file_content,err:=ioutil.ReadFile(m3u8FileName)
        if err!=nil {
        	fmt.Println(err)
		return ""
        }

        s:=strings.Split(string(file_content),"\n")
        if len(s)<2 {
        	fmt.Printf("Wrong format for m3u8 file!\n")
		return ""
        }
	
        filename:=s[len(s)-2]
	return filename
}

func uploadFile(tsFileName string,m3u8FileName string) {
	var loopcnt1 int=0
	var loopcnt2 int=0
	isTsUpload:=false
	isM3u8Upload:=false
	filename:=getTsFileName(m3u8FileName)
	
	if filename=="" {
		return
	}
	
	for {
		if !(isTsUpload||(loopcnt1==5))  {
			err:=putFile(tsFileName,filename,client)
        		if err!=nil {
                        	fmt.Println(err)
                        	loopcnt1=loopcnt1+1
                	} else {
				isTsUpload=true
			}
		}
		if !(isM3u8Upload||(loopcnt2==5)) {
                	err:=putFile(m3u8FileName,"index.m3u8",client)
                	if err!=nil {   
                		fmt.Println(err)
				loopcnt2=loopcnt2+1
			} else {
				isM3u8Upload=true
			}
		}
		if (isTsUpload||loopcnt1==5)&&(isM3u8Upload||loopcnt2==5) {
			err:=os.Remove(tsFileName)
                        if err!=nil {
                        	fmt.Println(err)
                        }
			err=os.Remove(m3u8FileName)
			if err!=nil {
				fmt.Println(err)
			}
			break
		}
	}
}

func upload() {
	var tsFileName   string
	var m3u8FileName string
	fmt.Printf("upload is started.\n")	
	tNow := time.Now()
        timeNow := tNow.Format("2006-01-02 15:04:05")
        timeStampNow, _ := parseTimetoStamp(timeNow, httpLog)
	
        filePrefix:=int(timeStampNow)-delay
	fmt.Printf("filePrefix is %s.\n",filePrefix)
	tsFileName=fmt.Sprintf("%s/%d.ts",SrsDir,filePrefix)
	m3u8FileName=fmt.Sprintf("%s/%d.m3u8",SrsDir,filePrefix)
	
	if (!(checkFileNotExist(tsFileName)||checkFileNotExist(m3u8FileName))){
		uploadFile(tsFileName,m3u8FileName)
	}
	
	timer1:=time.NewTicker(time.Duration(10)*time.Second)
	for {
		select {	
			case <-timer1.C:
				 filePrefix=filePrefix+10
				 tsFileName=fmt.Sprintf("%s/%d.ts",SrsDir,filePrefix)
       				 m3u8FileName=fmt.Sprintf("%s/%d.m3u8",SrsDir,filePrefix)
				 if (!(checkFileNotExist(tsFileName)||checkFileNotExist(m3u8FileName))){
					uploadFile(tsFileName,m3u8FileName)
				 }
		}
	}
}

func main() {
	defer func() {
                if err:=recover();err!=nil {
                        httpLog.Println(err)
                }
        }()
        logFile, err := os.Create("./upload.log")
        defer logFile.Close()
        if err != nil {
                fmt.Printf("Open file error!\n")
        }

	httpLog= log.New(logFile, "[Info]", log.Ldate|log.Ltime|log.Lshortfile)
	httpLog.Printf("ok!\n")

	//Start parsing input parameters
	arg_num :=len(os.Args)

	if arg_num!=5 {
		httpLog.Printf("arg_num is %d.\n",arg_num)
		return
	}

	timout,err=strconv.Atoi(os.Args[1])
	if err!=nil{
		httpLog.Println(err)
		return
	}

	delay,err=strconv.Atoi(os.Args[2])	
	RemoteUrl=os.Args[3]
	SrsDir=os.Args[4]
	fmt.Printf("transcode_upload: remote_dir == %s\n",RemoteUrl)
	fmt.Printf("transcode_upload: local_dir  == %s\n",SrsDir)
	//End parsing input parameters.

	client=initHttpl()
	timer2:=time.NewTicker(time.Duration(50)*time.Millisecond)
	isDelayTime:=false
	fetchTime=false

	for {
		if (!isDelayTime){
			select {
       				case <-httpchan:
                			go upload()
                			httpLog.Printf("Start to upload files for the delay time comes.\n")
					isDelayTime=true
					break
				case <-timer2.C:
					break
			}
		}
		renameFile()
	}
}						
					
















								
				
	
